package com.atguigu.gmall.gateway.filter;

import com.alibaba.nacos.client.utils.IPUtil;
import com.atguigu.gmall.common.utils.CookieUtils;
import com.atguigu.gmall.common.utils.IpUtils;
import com.atguigu.gmall.common.utils.JwtUtils;
import com.atguigu.gmall.gateway.config.JwtProperties;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/*
网关局部过滤器
 */
@Component
@EnableConfigurationProperties(JwtProperties.class)
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.ValueConfig> {

    public AuthGatewayFilterFactory(){
        super(AuthGatewayFilterFactory.ValueConfig.class);
    }

    @Autowired
    JwtProperties jwtProperties;

    @Override
    public ShortcutType shortcutType() {
        //list类型
        return ShortcutType.GATHER_LIST;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("params");
    }
    @Override
    public GatewayFilter apply(ValueConfig config) {

        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                ServerHttpResponse response = exchange.getResponse();
                //判读是否是拦截路径
                String path = request.getURI().getPath();
                //如果等于空则拦截所有路径
                List<String> params = config.params;
                if (!CollectionUtils.isEmpty(params)&&params.stream().allMatch(item->path.startsWith(item)==false)){
                    return chain.filter(exchange);
                }
                //判断是否带有token
                String token = request.getHeaders().getFirst("token");
                if (StringUtils.isBlank(token)){
                    MultiValueMap<String, HttpCookie> cookies = request.getCookies();
                    token = cookies.getFirst(jwtProperties.getCookieName()).getValue();
                }
                if (StringUtils.isBlank(token)){
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION, "http://sso.gmall.com/toLogin.html?returnUrl=" + request.getURI());
                    return response.setComplete();
                }
                //解析token 判读是否正确
                try {
                    Map<String, Object> map = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
                    //获取载荷中的ip地址 合 传递过来的ip地址是否相同 防盗链
                    String ip = map.get("ip").toString();
                    String ipAddressAtGateway = IpUtils.getIpAddressAtGateway(request);
                    if (!StringUtils.equals(ip,ipAddressAtGateway)){
                        response.setStatusCode(HttpStatus.SEE_OTHER);
                        response.getHeaders().set(HttpHeaders.LOCATION, "http://sso.gmall.com/toLogin.html?returnUrl=" + request.getURI());
                        return response.setComplete();
                    }
                    //传递载荷信息给后续服务 后续服务则不需要在次解析
                    request.mutate().header("userId",map.get("userId").toString())
                            .header("username",map.get("username").toString()).build();
                    exchange.mutate().request(request).build();
                    //放行
                    return chain.filter(exchange);
                } catch (Exception e) {
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://sso.gmall.com/toLogin.html?returnUrl="+ request.getURI());
                    return response.setComplete();
                }
            }
        };
    }

    @Data
    public static class ValueConfig{
        private List<String> params;
    }

}
